package codepulse.blogmoon.cn.code.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import codepulse.blogmoon.cn.code.entity.CodeAuthDetail;
import codepulse.blogmoon.cn.code.enums.SourceEnum;
import codepulse.blogmoon.cn.code.service.CodeAuthDetailService;
import codepulse.blogmoon.cn.code.vo.gitea.GetAuthAccessTokenRespVO;
import codepulse.blogmoon.cn.code.vo.gitea.GiteaAuthContnetVO;
import codepulse.blogmoon.cn.common.context.Context;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Maps;
import io.netty.handler.codec.http.HttpMethod;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Component
public class GiteaRestClient {

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private CodeAuthDetailService codeAuthDetailService;

    private String GITE_REST_AUTH_KEY = "GITE_REST_AUTH_KEY";


    public <T, V> T post(String url, V req, Class<T> clazz) {
        return request(Method.POST, url, JSONObject.parseObject(JSONObject.toJSONString(req), Map.class), clazz);
    }

    public <T> T post(String url, Map params, Class<T> clazz) {
        return request(Method.POST, url, params, clazz);
    }

    public <T, V> T get(String url, V req, Class<T> clazz) {
        return request(Method.GET, url, JSONObject.parseObject(JSONObject.toJSONString(req), Map.class), clazz);
    }

    public <T> T get(String url, Map<String, Object> params, Class<T> clazz) {
        return request(Method.GET, url, params, clazz);
    }


    public <T> T request(Method method, String url, Map params, Class<T> clazz) {
        String key = GITE_REST_AUTH_KEY.concat(":").concat(String.valueOf(Context.get().getBizAcctId()));
        CodeAuthDetail codeAuthDetail = getCodeAuthDetail();
        String token = (String) redisTemplate.opsForValue().get(key);
        if (StringUtils.isBlank(token)) {
            GetAuthAccessTokenRespVO respVO = getAuthToken(codeAuthDetail);
            if (Objects.nonNull(respVO) && StringUtils.isNotBlank(respVO.getAccessToken())) {
                redisTemplate.opsForValue().set(key, respVO.getAccessToken(), respVO.getExpiresIn() - 1000, TimeUnit.SECONDS);
            }
        }
        HttpRequest request = HttpUtil.createRequest(method, codeAuthDetail.getUrl().concat(url));
        String resp = request.header("Authorization", "token " + token).form(params)
                .timeout(20000).execute().body();
        return JSONObject.parseObject(resp, clazz);
    }

    private GetAuthAccessTokenRespVO getAuthToken(CodeAuthDetail codeAuthDetail) {
        Map<String, Object> map = Maps.newHashMap();
        map.put("client_id", codeAuthDetail.getAppId());
        map.put("client_secret", codeAuthDetail.getSecret());
        map.put("grant_type", "authorization_code");
        map.put("code", JSONObject.parseObject(codeAuthDetail.getAuthContent(), GiteaAuthContnetVO.class).getCode());
        String resp = HttpUtil.post(codeAuthDetail.getUrl().concat("/login/oauth/access_token"), map);
        return JSONObject.parseObject(resp, GetAuthAccessTokenRespVO.class);
    }

    private CodeAuthDetail getCodeAuthDetail() {
        CodeAuthDetail codeAuthDetail = codeAuthDetailService.getOne(Wrappers.<CodeAuthDetail>lambdaQuery()
                .eq(CodeAuthDetail::getSource, SourceEnum.GITEA.getType()));
        return codeAuthDetail;
    }

}
